package io.gitee.bowen_lee.rpc;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.util.UUID;

import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * 1. 自定义RPC
 * 2. server端,客户端通信,连接数量config, 占包,粘包
 * 3. 动态代理,序列化,协议封装
 * 4. 连接池
 * 5. sdk封装 面向interface 开发
 * 
 * 
 * 
 * (动态代理是一种封装 接口 的 形式.还可以使用抽象类的方式来封装sdk)
 * 
 * @author Bowen
 * @since 2022-01-17 15:53:08
 */
public class MyRPCTest {
  public static void main(String[] args) {
    Car car = getProxyCar(Car.class);
    car.ooxx("hello world!");
  }

  /**
   * 实现各个版本的动态代理
   * 
   * @param <T>
   * @param interfaceInfo
   * @return
   */
  @SuppressWarnings("all")
  public static <T> T getProxyCar(Class<T> interfaceInfo) {

    Class<?>[] interfaces = { interfaceInfo };
    ClassLoader classLoader = interfaceInfo.getClassLoader();
    return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
      // 封装 content
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 设计 consumer 对 provider 的调用过程
        // 1.调用方法 ,参数,服务封装
        // msg 组装
        MyContent content = new MyContent(interfaceInfo.getName(), method.getParameterTypes(), method.getName());

        // body转字节数组
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream oout = new ObjectOutputStream(out);
        oout.writeObject(content);
        byte[] msgBody = out.toByteArray();

        // requestId+ msg , 组装头部(requestId).
        BowenHeader header = createHeader(out.toByteArray());

        // 重置,然后 写入头部 对象
        out.reset();
        oout = new ObjectOutputStream(out);
        oout.writeObject(header);
        // 数据头
        byte[] msgHeader = out.toByteArray();

        // 连接池
        BowenClientFacory factory = BowenClientFacory.getFactory();
        NioSocketChannel channel = factory.getclient(new InetSocketAddress("127.0.0.1", 9090));
        // write and push
        // channel.writeandflash();

        System.out.println("ASD");
        method.invoke(proxy, args);
        System.out.println("asdasd");
        return null;
      }

    });

  }

  public static BowenHeader createHeader(byte[] msgbody) {
    BowenHeader header = new BowenHeader();

    int size = msgbody.length;
    int f = 0x14141414;// 十六进制 相当于 1位是4个字节
    long requestID = Math.abs(UUID.randomUUID().getLeastSignificantBits());
    header.setDataLen(size);
    header.setFlag(f);
    header.setRequestID(requestID);
    return header;
  }

  interface Car {
    public void ooxx(String msg);
  }

  class CarImpl implements Car {

    @Override
    public void ooxx(String msg) {
      System.out.println(msg);
    }

  }

class MyContent implements Serializable {
  private String name;
  private Class<?>[] methodParameterTypes;
  private String mothodName;

  public MyContent() {
  }

  public MyContent(String name, Class<?>[] methodParameterTypes, String mothodName) {
    this.name = name;
    this.methodParameterTypes = methodParameterTypes;
    this.mothodName = mothodName;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Class<?>[] getMethodParameterTypes() {
    return methodParameterTypes;
  }

  public void setMethodParameterTypes(Class<?>[] methodParameterTypes) {
    this.methodParameterTypes = methodParameterTypes;
  }

  public String getMothodName() {
    return mothodName;
  }

  public void setMothodName(String mothodName) {
    this.mothodName = mothodName;
  }

}